#!/usr/bin/env python
# -*- coding: utf8 -*-
import os
import logging


import tornado
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.template
from tornado.options import define, options


define("port", default=8001, help="run on the given port", type=int)

logging.basicConfig(level=logging.DEBUG, format="%(levelname)s - %(asctime)s - line:%(lineno)d - %(message)s")


def autodelegate(prefix):
    def internal(self, arg):
        if '/' in arg:
            first, rest = arg.split('/', 1)
            func = prefix + first
            args = ['/' + rest]
        else:
            func = prefix + arg
            args = []

        return getattr(self, func)(*args)

        # if hasattr(self, func):
        #     try:
        #         return getattr(self, func)(*args)
        #     except TypeError:
        #         raise web.notfound()
        # else:
        #     raise web.notfound()
    return internal


class State(object):

    # 发送startapp命令，等待启动app
    WAITING_STARTAPP = 'waiting-startapp'
    # 发送stopapp命令，等待重启完毕
    WAITING_STOPAPP = 'waiting-stopapp'
    
    # 收到startapp命令，启动app完成
    FINISH_STARTAPP = 'finish-startapp'

    # 设备处于闲置状态
    IDLE = 'idle'

    def __init__(self, deviceId, stateManager):
        self.deviceId = deviceId
        self.stateManager = stateManager
        self._state = None

    @property
    def step(self):
        return self._state

    @step.setter
    def step(self, val):
        self._state = val

    @property
    def boundleId(self):
        return self._boundleId

    @boundleId.setter
    def boundleId(self, val):
        self._boundleId = val

    # 协议
    def protocalIdle(self):
        self.step = self.IDLE
        return self._return0()

    def protocalStopApp(self):
        self.step = self.WAITING_STOPAPP
        return self._return1('stopapp', self.boundleId)

    def protocalStartApp(self):
        self.step = self.WAITING_STARTAPP
        return self._return1('startapp', self.boundleId)

    def protocalFinishStartApp(self):
        self.step = self.FINISH_STARTAPP
        return self._return0()

    def _return(self, status, funcName='', *params):
        l = [str(status), funcName]
        l.extend([str(i) for i in params])
        r = ','.join(l)
        if r[-1] == ',':
            r = r[:-1]
        return r

    def _return1(self, funcName, *params):
        return self._return(1, funcName, *params)

    def _return0(self):
        return self._return(0)

    def handleReq(self, request):
        raise NotImplementedError('YOU NEED IMPLEMENT IN DRIVEN CLASS')

    def handleResp(self, request):
        raise NotImplementedError('YOU NEED IMPLEMENT IN DRIVEN CLASS')

    def isWaitingStep(self):
        return self.step.startswith('waiting')

    def isFinishStep(self):
        return self.step.startswith('finish')

    def isStartApp(self):
        return self.step in [self.FINISH_STARTAPP]


class StateException(Exception):
    pass


class KKPokerState(State):
    """
    登陆时奖励弹出框：http://120.132.32.53:8080/Sign/get_sign_config
    is_sign : 1已经签到，不会弹框 0 会弹框
    """

    def __init__(self, deviceId, stateManager):
        super(KKPokerState, self).__init__(deviceId, stateManager)
        self._boundleId = 'com.shuailai.kkpokerchinese'

    def handleReq(self, request):
        try:
            step = self.step
            # func = request.get('func')
            if self.IDLE == step:
                return self.protocalStartApp()

            if self.isStartApp() and not request.get('bundleId'):
                raise StateException('app state started, but no bundleId')

            return self._return0()
        except StateException:
            self.stateManager.removeState(self.deviceId)
            return self.protocalStopApp()

    def handleResp(self, request):

        try:
            step = self.step
            func = request.get('func')

            if self.WAITING_STARTAPP == step:
                if func != 'startapp':
                    raise StateException('currnet:%s, return:%s' % (self.WAITING_STARTAPP, func))
                return self.protocalFinishStartApp()

            return self._return0()
        except StateException:
            self.stateManager.removeState(self.deviceId)
            return self.protocalStopApp()


class StateManager(dict):

    def popTaskState(self, deviceId):
        # pop from queue 
        # if no task return None
        return KKPokerState(deviceId, self)

    def removeState(self, key):
        if key in self:
            del self[key]


sm = StateManager()


class Echo(tornado.web.RequestHandler):

    """
    appid: "com.shuailai.kkpokerchinese"
    0: 保持现有状态继续发送
    1: 有下一步操作
    """

    get = autodelegate('get_')

    # def _return(self, status, funcName='', *params):
    #     l = [str(status), funcName]
    #     l.extend([str(i) for i in params])
    #     r = ','.join(l)
    #     if r[-1] == ',':
    #         r = r[:-1]
    #     return r

    # def _return1(self, funcName, *params):
    #     return self._return(1, funcName, *params)

    # def _return0(self):
    #     return self._return(0)

    def _dictfy(self):
        args = self.request.arguments
        return {i: self.get_query_argument(i) for i in args}

    def get_heartjump(self):
        """
        协议：
        1）idle
        http://192.168.1.99:8001/api/heartjump?type=req&driverid=pppp
        返回 0: 没有后续操作，继续等待新的命令
        返回 1: 有后续操作，发送新的命令

        2) startapp
        http://192.168.1.99:8001/api/heartjump?type=resp&driverid=pppp&func=startapp&ret=0
        """

        ty = self.get_query_argument('type')
        deviceId = self.get_query_argument('driverId')
        boundleId = self.get_query_argument('boundleId', '')
        args = self._dictfy()
        state = sm.get(deviceId)

        logging.info("request:%s", str(args))

        if state:
            if ty == 'req':
                ret = state.handleReq(args)
            elif ty == 'resp':
                ret = state.handleResp(args)
            else:
                raise ValueError('unkown type:' + ty)
        else:
            state = sm.popTaskState(deviceId)
            if state:
                sm[deviceId] = state
                if boundleId:
                    ret = state.protocalStopApp()
                else:
                    ret = state.protocalIdle()
            else:
                ret = State(deviceId).protocalIdle()

        logging.info("response:%s", ret)
        return self.write(ret)

    def handle_req(self):
        pass

    def handle_resp(self):
        pass
    # def get_startapp(self):
    #     # driverid = self.get_query_argument('driverid')
    #     return self.write(self._return0())

Handlers = [(r"/api/(.*)", Echo), ]


class Application(tornado.web.Application):
    """docstring for Application"""

    def __init__(self, **kwsetting):
        super(Application, self).__init__()

        # super(Application, self).__init__(static_path=htmlpath,
        #                                   static_url_prefix='/static',
        #                                   **kwsetting)
        kwsetting.update({
            "template_path": os.path.join(os.path.dirname(__file__), "templates"),
            "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=",
            "xsrf_cookies": True,
            "log_function": self.log,
        })
        super(Application, self).__init__(
            **kwsetting)

    def log(self, handler):
        print "ip={ip}\nstatus={status}\nmethod={method}\npath{path}\ncontent={content}\n".format(
            status=handler.get_status(),
            method=handler.request.method,
            path=handler.request.uri,
            ip=handler.request.remote_ip,
            content='',)

if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = Application(handlers=Handlers, debug=True)
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    logging.info("Starting HTTP proxy on port %d" % options.port)
    tornado.ioloop.IOLoop.instance().start()
